﻿using System;

namespace UtilZ.Dotnet.Ex.Audio
{
    /// <summary>
    /// 音频信息
    /// </summary>
    public class WaveInfo
    {
        /// <summary>
        /// 音频文件路径
        /// </summary>
        public string FilePath { get; set; } = null;

        /// <summary>
        /// 编码格式
        /// </summary>
        public WaveEncoding Encoding { get; private set; }

        /// <summary>
        /// 采样率
        /// </summary>
        public int SampleRate { get; private set; }

        /// <summary>
        /// 声道数
        /// </summary>
        public short ChannelCount { get; private set; }

        /// <summary>
        /// 采样位数
        /// </summary>
        public int SampleBits { get; private set; }

        /// <summary>
        /// fact值,大于0有效
        /// </summary>
        public int Fact { get; private set; } = 0;

        /// <summary>
        /// 否存在fact数据块[true:存在;false:不存在]
        /// </summary>
        public bool HasFact { get; private set; } = false;

        private readonly int _trunkSize = 0;
        /// <summary>
        /// 数据传输速率(每秒播放数据长度、播放速度、传输速度),含义:播波形数据传输速率（每秒平均字节数,每秒所需播放字节数）,也叫Bite率;
        /// </summary>
        public int TrunkSize
        {
            get { return this._trunkSize; }
        }

        private readonly short _blockAlign;
        /// <summary>
        /// 数据块对齐单位(单个数据点所占字节数),PCM的计算公式为：声道数×采样位数/8
        /// </summary>
        public short BlockAlign
        {
            get { return this._blockAlign; }
        }

        /// <summary>
        /// 音频数据的总长度字节数
        /// </summary>
        public uint WaveDataLength { get; private set; } = 0;



        /// <summary>
        /// 点数据长度
        /// </summary>
        public uint PointLength { get; private set; } = 0;

        /// <summary>
        /// 播放持续时长,单位:秒
        /// </summary>
        public double DurationSeconds { get; private set; } = 0d;


        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="encoding">编码格式</param>
        /// <param name="sampleRate">采样率</param>
        /// <param name="trunkSize">数据传输速率</param>
        /// <param name="blockAlign">数据块对齐单位</param>
        /// <param name="channelCount">声道数[1-6]</param>
        /// <param name="sampleBits">采样类型(采样位位)</param>
        /// <param name="fact">act</param>
        /// <param name="waveDataLength">音频数据的总长度字节点</param>
        internal WaveInfo(WaveEncoding encoding, int sampleRate, int trunkSize, short blockAlign, short channelCount, short sampleBits, int fact, uint waveDataLength)
        {
            this.Encoding = encoding;
            this.SampleRate = sampleRate;
            this._trunkSize = trunkSize;
            this._blockAlign = blockAlign;
            this.ChannelCount = channelCount;
            this.SampleBits = sampleBits;
            this.Fact = fact;
            this.HasFact = fact > 0;
            this.WaveDataLength = waveDataLength;
            this.PointLength = (uint)(waveDataLength / blockAlign);
            this.DurationSeconds = (double)waveDataLength / trunkSize;
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="encoding">编码格式</param>
        /// <param name="sampleRate">采样率</param>
        /// <param name="chs">声道数[1-6]</param>
        /// <param name="sampleBits">采样类型(采样位位)</param>
        public WaveInfo(WaveEncoding encoding, int sampleRate, short chs, short sampleBits)
        {
            switch (encoding)
            {
                case WaveEncoding.Pcm:
                    this._trunkSize = chs * sampleBits * sampleRate / 8;
                    this._blockAlign = (short)(chs * sampleBits / 8);
                    break;
                case WaveEncoding.IeeeFloat:
                    sampleBits = 32;
                    this._trunkSize = chs * sampleBits * sampleRate / 8;
                    this._blockAlign = (short)(chs * sampleBits / 8);
                    break;
                case WaveEncoding.ALaw:
                case WaveEncoding.MuLaw:
                    this._trunkSize = chs * sampleRate;
                    this._blockAlign = chs;
                    break;
                case WaveEncoding.Adpcm:
                    this._blockAlign = WaveHelper.CaculateAdpcmBlockAlign(sampleRate);
                    short samplesPerBlock;
                    this._trunkSize = WaveHelper.CaculateAdpcmTrunkSize(sampleRate, this._blockAlign, chs, sampleBits, out samplesPerBlock);
                    break;
                case WaveEncoding.IbmCvsd:
                    throw new NotImplementedException($"{WaveEncoding.IbmCvsd}未实现的头计算.");
            }

            this.Encoding = encoding;
            this.SampleRate = sampleRate;
            this.ChannelCount = chs;
            this.SampleBits = sampleBits;
        }


        /// <summary>
        /// 重写ToString
        /// </summary>
        /// <returns>String</returns>
        public override string ToString()
        {
            return $"Encoding:{this.Encoding.ToString()},SampleRate:{this.SampleRate},SampleBits:{this.SampleBits},ChannelCount:{this.ChannelCount}";
        }


        /// <summary>
        /// 计算指定长度数据可播放时长,单位s
        /// </summary>
        /// <param name="length"></param>
        /// <returns>可播放时长</returns>
        public double CalateDurationSeconds(int length)
        {
            return (double)length / this._trunkSize;
        }

        /// <summary>
        /// 计算指定长度数据可播放时长,单位s
        /// </summary>
        /// <param name="length"></param>
        /// <returns>可播放时长</returns>
        public double CalateDurationSeconds(long length)
        {
            return (double)length / this._trunkSize;
        }

    }
}
